package com.alibaba.citrus.ots.sales.plan.facade.service.salesplan;

import com.alibaba.citrus.ots.common.annotation.EpochTransactional;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.citrus.ots.sales.plan.annotation.CommonRedisLock;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanLineQueryService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanLineWriteService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanQueryService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanWriteService;
import com.alibaba.citrus.ots.sales.plan.api.setting.SalesPlanScItemQueryService;
import com.alibaba.citrus.ots.sales.plan.api.statistics.SalesPlanScItemStatQueryService;
import com.alibaba.citrus.ots.sales.plan.api.statistics.SalesPlanScItemStatWriteService;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.BatchQuerySalesPlanScItemRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.CreateSalesPlanTemplateRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.EditDepartmentTaskRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.EditPublishStatusRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.PageQueryPlanLineRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.PageQuerySalePlanRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QueryPlanScItemStatRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QuerySalesPlanRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.UpdateTaskCountRequest;
import com.alibaba.citrus.ots.sales.plan.facade.service.SalesPlanCommonService;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.SalesPlanEntity;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.SalesPlanScItemStatAbility;
import com.alibaba.citrus.ots.sales.plan.model.SalesPlanLineStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.SalesPlanScItemStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesPlanModelEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesStatBizTypeEnum;
import com.alibaba.citrus.ots.sales.plan.repository.PlatformEnhanceRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanLineRepository;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanLineSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanScItemSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanStatScItemSDO;
import com.alibaba.cz.base.tool.StringUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otsplatformenhance.model.dto.CustomerAddressIndex;
import com.epoch.app.otsplatformenhance.opecustomeraddressindex.dto.PageQueryCustomerAddressFilterRequest;
import com.epoch.app.otsplatformenhance.opecustomeraddressindex.dto.PageQueryCustomerAddressFilterResponse;
import com.epoch.app.otsplatformenhance.opecustomeraddressindex.service.OpeCustomerAddressIndexService;
import com.epoch.app.otsplatformenhance.sdo.OrganizationSDO;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.alibaba.citrus.ots.sales.plan.contants.SalesPlanLockKey.CREATE_SALES_PLAN_PREFIX;

@Service
public class SalesPlanWriteServiceImpl implements SalesPlanWriteService {
    private final Log log = Log.getLogger(SalesPlanWriteServiceImpl.class);

    @Resource
    private SalesPlanQueryService salesPlanQueryService;

    @Resource
    private SalesPlanScItemStatWriteService salesPlanScItemStatWriteService;

    @Resource
    private SalesPlanScItemStatQueryService salesPlanScItemStatQueryService;

    @Resource
    private SalesPlanScItemStatAbility salesPlanScItemStatAbility;

    @Resource
    private PlatformEnhanceRepository platformEnhanceRepository;

    @Resource
    private SalesPlanLineWriteService salesPlanLineWriteService;

    @Resource
    private SalesPlanLineQueryService salesPlanLineQueryService;

    @Resource
    private SalesPlanScItemQueryService salesPlanScItemQueryService;

    @Resource
    private SalesPlanLineRepository salesPlanLineRepository;

    @Resource
    private SalesPlanCommonService salesPlanCommonService;

    @Resource
    private EpochMessageService epochMessageService;

    /**
     * 计划明细page_size
     */
    private static final Integer SALES_PLAN_LIN_PAGE_SIZE = 500;

    @Override
    @FacadeInvoker
    @CommonRedisLock(redisLockPrefix = CREATE_SALES_PLAN_PREFIX)
    public Result<String> createSalesPlan(SalesPlanSDO salesPlanSDO) {
        Result result = checkParameter(salesPlanSDO);
        if (result != null) return result;
        // 构造实体
        SalesPlanEntity salesPlanEntity = SalesPlanEntity.of(salesPlanSDO);
        if (StringUtil.isNotEmpty(salesPlanSDO.getPlanTime())) {
            salesPlanSDO.setPlanTime(DateUtils.dateToStamp(salesPlanSDO.getPlanTime() + "-01 00:00:00"));
        }
        String lastInsertId = salesPlanEntity.save();
        //生成模板
        if (StringUtils.isNotBlank(lastInsertId)) {
            try {
                log.info("SalesPlanWriteServiceImpl#createSalesPlan#sendMessage:" + lastInsertId);
                epochMessageService.sendMessage("sales_plan_template", "CR_SALES_PLAN", "sales_plan_template", lastInsertId);
            } catch (Exception e) {
                log.error("SalesPlanWriteServiceImpl#createSalesPlan#sendMessage_fail  ", e);
            }
        }
        return Result.success(lastInsertId);
    }

    @Nullable
    private Result checkParameter(SalesPlanSDO salesPlanSDO) {
        //时间校验
        //计划年月不能小于当前年月
        if (StringUtil.isNotEmpty(salesPlanSDO.getPlanTime())) {
            String planTime = salesPlanSDO.getPlanTime();
            //当前时间
            Date currentTime = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
            String formatterPlanTime = formatter.format(currentTime);
            int compareTo = planTime.compareTo(formatterPlanTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("planTime", "请填写合适的计划年月");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //提报开始结束时间不能为空
        if (null == salesPlanSDO.getStartTime() || null == salesPlanSDO.getEndTime()) {
            Result result = new Result();
            result.setSuccess(false);
            Map<String, Object> validateErrors = new HashMap<>();
            validateErrors.put("reportTime", "提报起止时间 是必填字段");
            result.setValidateErrors(validateErrors);
            return result;
        }

        //提报开始时间不能小于当前时间
        if (null != salesPlanSDO.getStartTime()) {
            //当前时间
            Date currentTime = new Date();
            Date startTime = salesPlanSDO.getStartTime();
            int compareTo = startTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报开始时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }


        //提报结束不能小于当前时间
        if (null != salesPlanSDO.getEndTime()) {
            //当前时间
            Date currentTime = new Date();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报结束时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //提报结束时间不能大于提报开始时间
        if (null != salesPlanSDO.getStartTime() && null != salesPlanSDO.getEndTime()) {
            Date startTime = salesPlanSDO.getStartTime();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(startTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报结束时间应在提报开始时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //三旬均衡比例总和须等于100%
        BigDecimal sum = salesPlanSDO.getMonthFirstProprtion().add(salesPlanSDO.getMonthMiddleProprtion()).add(salesPlanSDO.getMonthLastProprtion());
        if (new BigDecimal(100).compareTo(sum) != 0) {
            throw new FacadeException("OTS-02-002-01-15-012");
        }
        //销售组织”+“计划年月”进行校验该数据是否存在
        //start
        PageQuerySalePlanRequest querySalePlanRequest = new PageQuerySalePlanRequest();
        querySalePlanRequest.setOrgBusinessUnitCode(salesPlanSDO.getOrgBusinessUnitCode());
        querySalePlanRequest.setPlanTime(salesPlanSDO.getPlanTime());
        Result<PageResult<List<SalesPlanSDO>>> pageResultResult = salesPlanQueryService.pageQuerySalesPlanList(querySalePlanRequest);
        if (pageResultResult.getResult().getContent().size() > 0) {
            throw new FacadeException("OTS-02-002-01-15-011");
        }
        //end
        return null;
    }

    @Override
    @FacadeInvoker
    public Result<Boolean> editSalesPlan(SalesPlanSDO salesPlanSDO) {
        if (null == salesPlanSDO.getId()) {
            throw new FacadeException("OTS-02-002-02-15-008");
        }
        salesPlanCommonService.checkSalesPlan(salesPlanSDO.getId().toString());
        Result result = checkTime(salesPlanSDO);
        if (result != null) return result;
        //时间处理
        if (StringUtil.isNotEmpty(salesPlanSDO.getPlanTime())) {
            salesPlanSDO.setPlanTime(DateUtils.dateToStamp(salesPlanSDO.getPlanTime() + "-01 00:00:00"));
        }
        SalesPlanEntity salesPlanEntity = SalesPlanEntity.of(salesPlanSDO);
        return Result.success(salesPlanEntity.edit());
    }

    @Nullable
    private Result checkTime(SalesPlanSDO salesPlanSDO) {
        //提报开始结束时间不能为空
        if (null == salesPlanSDO.getStartTime() || null == salesPlanSDO.getEndTime()) {
            Result result = new Result();
            result.setSuccess(false);
            Map<String, Object> validateErrors = new HashMap<>();
            validateErrors.put("reportTime", "提报起止时间 是必填字段");
            result.setValidateErrors(validateErrors);
            return result;
        }

        //提报开始时间不能小于当前时间
        if (null != salesPlanSDO.getStartTime()) {
            //当前时间
            Date currentTime = new Date();
            Date startTime = salesPlanSDO.getStartTime();
            int compareTo = startTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报开始时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }
        //提报结束不能小于当前时间
        if (null != salesPlanSDO.getEndTime()) {
            //当前时间
            Date currentTime = new Date();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报结束时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //提报结束时间不能大于提报开始时间
        if (null != salesPlanSDO.getStartTime() && null != salesPlanSDO.getEndTime()) {
            Date startTime = salesPlanSDO.getStartTime();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(startTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("reportTime", "提报结束时间应在提报开始时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }
        return null;
    }

    @Override
    @FacadeInvoker
    @Deprecated
    public Result<Boolean> reply(List<SalesPlanStatScItemSDO> updateSalesPlanRequest) {
        // 1、第三方接口同步 根据plan_id,sc_item_id 业务单元BizId,bizType,调用update接口更新 month_first_return_cout,task 上中下旬回复量，任务量
        //更新业务单元维度 回复量、任务量
        updateSalesPlanRequest.forEach(scItemStat -> {
           /* // 回复量>=计划量则直接更新,并进行部门任务拆解
            if (scItemStat.getReturnCount() >= scItemStat.getTaskCount()) {
                SalesPlanStatScItemSDO statSDO = new SalesPlanStatScItemSDO();
                BeanUtils.copyProperties(scItemStat, statSDO);
                // 任务金额 = 任务量*到岸价
                BigDecimal taskMoney = new BigDecimal(statSDO.getTaskCount()).multiply(new BigDecimal(statSDO.getCostInsuranceFreight()));
                statSDO.setTaskMoney(taskMoney.longValue());
                salesPlanScItemStatWriteService.editSalesPlanScItem(statSDO).getResult();
            } else {

            }*/
        });
        // 2、按照业务单元id进行分组
        Map<String, List<SalesPlanStatScItemSDO>> bussinessUnitMap = updateSalesPlanRequest.stream().collect(Collectors.groupingBy(SalesPlanStatScItemSDO::getBizId));
        // 3、根据业务单元,查询所有部门
        List<String> departments = new ArrayList<>();
        for (String bussinessUnitCode : bussinessUnitMap.keySet()) {
            List<OrganizationSDO> departmentList = platformEnhanceRepository.queryOrganizationByBizId("COMPANY", bussinessUnitCode, "106");
            List<String> departmentCodes = departmentList.stream().map(OrganizationSDO::getId).distinct().collect(Collectors.toList());
            departments.addAll(departmentCodes);
        }
        // 3、查询对应业务单元下所有部门的货品维度数据
        List<SalesPlanStatScItemSDO> salesPlanScItemStatList = new ArrayList<>();
        updateSalesPlanRequest.forEach(salePlanRequest -> {
            QueryPlanScItemStatRequest request = new QueryPlanScItemStatRequest();
            request.setPlanId(Long.parseLong(salePlanRequest.getPlanId()));
            request.setScItemId(salePlanRequest.getScItemId());
            //部门维度
            request.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
            // 部门id
            request.setBizIds(departments);
            request.setStart(0);
            request.setLimit(1000);
            // 批量查询
            PageResult<List<SalesPlanStatScItemSDO>> pageResult =
                    salesPlanScItemStatQueryService.batchQueryPlanScItemByBizId(request).getResult();
            List<SalesPlanStatScItemSDO> scItemStatSDOList = pageResult.getContent();
            salesPlanScItemStatList.addAll(scItemStatSDOList);
        });
        // 更新部门回复量等于部门计划量
        salesPlanScItemStatAbility.doSplit(salesPlanScItemStatList);
        // 4、更新计划状态为待发布
        updatePlanStatus(updateSalesPlanRequest);
        return Result.success(true);
    }

    /**
     * 失焦更新部门任务量
     *
     * @param editDepartmentTaskRequest
     * @return
     */

    @Override
    @FacadeInvoker
    public Result<Boolean> updateDepartmentTask(EditDepartmentTaskRequest editDepartmentTaskRequest) {
        QueryPlanScItemStatRequest request = new QueryPlanScItemStatRequest();
        request.setId(String.valueOf(editDepartmentTaskRequest.getId()));
        SalesPlanStatScItemSDO scItemStatSDO = salesPlanScItemStatQueryService.queryPlanScItemById(request).getResult();
        BigDecimal taskMoney = new BigDecimal(editDepartmentTaskRequest.getTaskCount()).multiply(new BigDecimal(scItemStatSDO.getCostInsuranceFreight()));
        scItemStatSDO.setTaskMoney(taskMoney.longValue());
        scItemStatSDO.setTaskCount(editDepartmentTaskRequest.getTaskCount());
        scItemStatSDO.setMonthFirstTaskCount(editDepartmentTaskRequest.getMonthFirstTaskCount());
        scItemStatSDO.setMonthMiddleTaskCount(editDepartmentTaskRequest.getMonthMiddleTaskCount());
        scItemStatSDO.setMonthLastTaskCount(editDepartmentTaskRequest.getMonthLastTaskCount());
        return salesPlanScItemStatWriteService.editSalesPlanScItem(scItemStatSDO);
    }

    /**
     * 更新计划货品状态为待发布
     *
     * @param editPublishStatusRequest
     * @return
     */
    @Override
    @FacadeInvoker
    public Result<Boolean> updatePublishStatus(EditPublishStatusRequest editPublishStatusRequest) {
        QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
        queryPlanScItemStatRequest.setPlanId(editPublishStatusRequest.getPlanId());
        queryPlanScItemStatRequest.setScItemId(editPublishStatusRequest.getScItemId());
        queryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
        // 查询部门维度该计划货品数据
        List<SalesPlanStatScItemSDO> salesPlanScItemStatSDOList = salesPlanScItemStatQueryService.queryPlanScItemByPlanId(queryPlanScItemStatRequest).getResult();
        List<Long> ids = salesPlanScItemStatSDOList.stream().map(it -> it.getId()).collect(Collectors.toList());
        SalesPlanStatScItemSDO salesPlanScItemStatSDO = new SalesPlanStatScItemSDO();
        //salesPlanScItemStatSDO.setIds(ids);
        salesPlanScItemStatSDO.setStatus(SalesPlanScItemStatusEnum.TO_BE_PUBLISH.getCode());
        // 更新状态为待发布
        Result<Boolean> result = salesPlanScItemStatWriteService.batchEditPlanScItem(salesPlanScItemStatSDO);
        // 任务数据拆解，向上层汇总
        dispatchTask(salesPlanScItemStatSDOList);
        return result;
    }

    /**
     * 更新月度计划状态为待发布
     *
     * @param updateSalesPlanRequest
     */
    private void updatePlanStatus(List<SalesPlanStatScItemSDO> updateSalesPlanRequest) {
        List<String> planIds = updateSalesPlanRequest.stream().map(SalesPlanStatScItemSDO::getPlanId).collect(Collectors.toList());
        planIds.forEach(planId -> {
            SalesPlanSDO planSDO = new SalesPlanSDO();
            planSDO.setId(Long.parseLong(planId));
            planSDO.setStatus(SalesPlanStatusEnum.TO_BE_PUBLISHED.getCode());
            updateSalesPlanStatus(planSDO);
        });
    }

    @Override
    @FacadeInvoker
    @EpochTransactional(appCode = "bc_ots", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<Boolean> dispatchTask(List<SalesPlanStatScItemSDO> updateSalesPlanRequest) {
        // 5、渠道任务量 = 部门计划量
        dispatchParentTask(updateSalesPlanRequest, SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
        // 6、 组织任务量 = 渠道计划量
        List<SalesPlanStatScItemSDO> channelSalesPlanScItemStatSDO = new ArrayList<>();
        updateSalesPlanRequest.forEach(salesPlanScItemStatSDO -> {
            QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
            queryPlanScItemStatRequest.setPlanId(Long.parseLong(salesPlanScItemStatSDO.getPlanId()));
            queryPlanScItemStatRequest.setScItemId(salesPlanScItemStatSDO.getScItemId());
            queryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALES_CHANNEL.getBizType());
            List<SalesPlanStatScItemSDO> salesPlanScItemStatSDOList = salesPlanScItemStatQueryService.queryPlanScItemByPlanId(queryPlanScItemStatRequest).getResult();
            channelSalesPlanScItemStatSDO.addAll(salesPlanScItemStatSDOList);
        });
        dispatchParentTask(channelSalesPlanScItemStatSDO, SalesStatBizTypeEnum.SALES_CHANNEL.getBizType());

        return Result.success(true);
    }

    /**
     * @param updateSalesPlanRequest
     * @return
     */
    private Map<String, List<OrganizationSDO>> getOrganizationRelation(List<SalesPlanStatScItemSDO> updateSalesPlanRequest) {
        // 1、获取计划货品组织ID
        List<String> bizIdList = updateSalesPlanRequest.stream().map(SalesPlanStatScItemSDO::getBizId).distinct().collect(Collectors.toList());
        // 2、批量查询组织相关信息
        List<OrganizationSDO> organizationSDOList = platformEnhanceRepository.queryOrganizationByIds(bizIdList);
        // 3、以parentId进行分组
        return organizationSDOList.stream().collect(Collectors.groupingBy(OrganizationSDO::getParentId));
    }

    private void dispatchParentTask(List<SalesPlanStatScItemSDO> updateSalesPlanRequest, Integer bizType) {
        Map<String, List<OrganizationSDO>> organizationRelationMap = getOrganizationRelation(updateSalesPlanRequest);
        for (String parentId : organizationRelationMap.keySet()) {
            // 渠道/组织id
            List<OrganizationSDO> organizationSDOList = organizationRelationMap.get(parentId);
            /*List<String> bizIds = organizationSDOList.stream().map(OrganizationSDO::getValue).collect(Collectors.toList());*/
            List<String> bizIds = new ArrayList<>();
            updateSalesPlanRequest.forEach(salesPlanScItemStatSDO -> {
                        setParentTaskCount(salesPlanScItemStatSDO, bizIds, bizType, parentId);
                    }
            );
        }
    }

    private void setParentTaskCount(SalesPlanStatScItemSDO salesPlanScItemStatSDO, List<String> bizIds, Integer bizType, String parentId) {
        // 1、按照计划、货品、部门/渠道, 查询需要汇总的数据
        QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
        queryPlanScItemStatRequest.setPlanId(Long.parseLong(salesPlanScItemStatSDO.getPlanId()));
        queryPlanScItemStatRequest.setScItemId(salesPlanScItemStatSDO.getScItemId());
        queryPlanScItemStatRequest.setBizIds(bizIds);
        queryPlanScItemStatRequest.setBizType(bizType);
        List<SalesPlanStatScItemSDO> salesPlanScItemStatSDOList = salesPlanScItemStatQueryService.queryPlanScItemByPlanId(queryPlanScItemStatRequest).getResult();
        // 2、计算某计划、货品下,该部门/渠道的任务量、上中下旬任务量总和
        int parentTaskCountSum = salesPlanScItemStatSDOList.stream().mapToInt(SalesPlanStatScItemSDO::getMonthCount).sum();
        int parentFirstTaskCountSum = salesPlanScItemStatSDOList.stream().mapToInt(SalesPlanStatScItemSDO::getMonthFirstCount).sum();
        int parentMiddleTaskCountSum = salesPlanScItemStatSDOList.stream().mapToInt(SalesPlanStatScItemSDO::getMonthMiddleCount).sum();
        int parentLastTaskCountSum = salesPlanScItemStatSDOList.stream().mapToInt(SalesPlanStatScItemSDO::getMonthLastCount).sum();
        // 3、更新某计划、货品下、汇总任务量
        // 若传入参数为2-部门维度，则汇总需查3-渠道维度
        // 若传入参数为3-渠道维度，则汇总需查4-组织维度
        Integer parentBizType = bizType + 1;
        queryPlanScItemStatRequest.setBizIds(null);
        queryPlanScItemStatRequest.setBizId(parentId);
        queryPlanScItemStatRequest.setBizType(parentBizType);
        // 4、根据计划ID，货品ID,渠道/组织ID获取计划货品信息
        List<SalesPlanStatScItemSDO> statSDOList = salesPlanScItemStatQueryService.queryPlanScItemByPlanId(queryPlanScItemStatRequest).getResult();
        statSDOList.forEach(statSDO -> {
            BigDecimal taskMoney = new BigDecimal(parentTaskCountSum).multiply(new BigDecimal(statSDO.getCostInsuranceFreight()));
            statSDO.setTaskMoney(taskMoney.longValue());
            statSDO.setTaskCount(parentTaskCountSum);
            statSDO.setMonthFirstTaskCount(parentFirstTaskCountSum);
            statSDO.setMonthMiddleTaskCount(parentMiddleTaskCountSum);
            statSDO.setMonthLastTaskCount(parentLastTaskCountSum);
            salesPlanScItemStatWriteService.editSalesPlanScItem(statSDO).getResult();
        });
    }

    @Override
    @FacadeInvoker
    @EpochTransactional(appCode = "bc_ots", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<Boolean> deploySalesPlan(SalesPlanStatScItemSDO salesPlanScItemStatSDO) {
        // 按照规则（待产品确定）， 计算客户任务量， 并更新
        // 1、查询发布计划所涉及的所有部门计划货品
        QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
        queryPlanScItemStatRequest.setPlanId(Long.valueOf(salesPlanScItemStatSDO.getPlanId()));
        queryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
        List<SalesPlanStatScItemSDO> salesPlanScItemStatSDOList = salesPlanScItemStatQueryService.queryPlanScItemByPlanId(queryPlanScItemStatRequest).getResult();
        List<String> departments = salesPlanScItemStatSDOList.stream().map(SalesPlanStatScItemSDO::getBizId).distinct().collect(Collectors.toList());
        // 2、查询发布部门下所有客户
        List<String> customerList = new ArrayList<>();
        departments.forEach(department -> {
            List<String> customer = platformEnhanceRepository.queryCustomerByBizType(department);
            customerList.addAll(customer);
        });
        // 3、通过客户编码查询月度对应计划明细
        PageQueryPlanLineRequest request = new PageQueryPlanLineRequest();
        //request.setCustomerCodes(customerList);
        Result<PageResult<List<SalesPlanLineSDO>>> pageResult = salesPlanLineQueryService.pageQuerySalesPlanLineList(request);
        List<SalesPlanLineSDO> firstPageContent = pageResult.getResult().getContent();
        int totalPages = (int) pageResult.getResult().getTotalPages();
        if (totalPages >= 1) {
            IntStream.range(2, totalPages).forEach(page -> {
                request.setPage(page);
                List<SalesPlanLineSDO> salePlanList = salesPlanLineQueryService.pageQuerySalesPlanLineList(request).getResult().getContent();
                firstPageContent.addAll(salePlanList);
            });
        }
        // 4、更新客户上中下旬任务量
        firstPageContent.forEach(salesPlanLineSDO -> {
                    // 客户任务量、上中下旬任务量=计划量
                    UpdateTaskCountRequest updateTaskCountRequest = new UpdateTaskCountRequest();
                    BeanUtils.copyProperties(salesPlanLineSDO, updateTaskCountRequest);
                    updateTaskCountRequest.setId(salesPlanLineSDO.getId());
                    updateTaskCountRequest.setTaskCount(salesPlanLineSDO.getMonthCount());
                    updateTaskCountRequest.setMonthFirstTaskCount(salesPlanLineSDO.getMonthFirstCount());
                    updateTaskCountRequest.setMonthMiddleTaskCount(salesPlanLineSDO.getMonthMiddleCount());
                    updateTaskCountRequest.setMonthLastTaskCount(salesPlanLineSDO.getMonthLastCount());
                    salesPlanLineWriteService.updateTaskCount(updateTaskCountRequest);
                }
        );
        return Result.success(true);
    }

    @Override
    @FacadeInvoker
    public Result<Integer> updateSalesPlanStatus(SalesPlanSDO salesPlanSDO) {
        if (null == salesPlanSDO.getId()) {
            throw new FacadeException("OTS-02-002-02-15-008");
        }
        salesPlanCommonService.checkSalesPlan(salesPlanSDO.getId().toString());
        SalesPlanEntity salesPlanEntity = SalesPlanEntity.of(salesPlanSDO);
        return Result.success(salesPlanEntity.updateSalesPlanStatus());
    }

    @Override
    @FacadeInvoker
    public Result<Boolean> createSalesPlanTemplate(CreateSalesPlanTemplateRequest createSalesPlanTemplateRequest) {
        if (StringUtil.isBlank(createSalesPlanTemplateRequest.getPlanId())) {
            throw new FacadeException("OTS-02-002-02-15-008");
        }
        // 根据ID+业务单元查询到计划年月
        QuerySalesPlanRequest querySalesPlanRequest = new QuerySalesPlanRequest();
        querySalesPlanRequest.setId(createSalesPlanTemplateRequest.getPlanId());
        Result<SalesPlanSDO> salesPlan = salesPlanQueryService.getSalesPlan(querySalesPlanRequest);
        if (null == salesPlan || null == salesPlan.getResult()) {
            throw new FacadeException("OTS-02-002-00-16-001");
        }

        // 查询到最近一个月的计划任务
        QuerySalesPlanRequest salesPlanRequest = new QuerySalesPlanRequest();
        salesPlanRequest.setPlanTime(DateUtils.dateToStamp(salesPlan.getResult().getPlanTime()));
        salesPlanRequest.setOrgBusinessUnitCode(salesPlan.getResult().getOrgBusinessUnitCode());
        salesPlanRequest.setModel(SalesPlanModelEnum.PLAN_MODEL.getModel());
        Result<SalesPlanSDO> salesPlanSDOResult = salesPlanQueryService.loadLatelySalesPlan(salesPlanRequest);
        if (null == salesPlanSDOResult || null == salesPlanSDOResult.getResult()) {
            log.error("SalesPlanWriteServiceImpl.createSalesPlanTemplate.not found parent salesPlan :planId = " + createSalesPlanTemplateRequest.getPlanId());
            return Result.success(true);
        }
        // 最近一个月的计划任务的明细
        PageQueryPlanLineRequest pageQueryPlanLineRequest = new PageQueryPlanLineRequest();
        pageQueryPlanLineRequest.setPlanId(salesPlanSDOResult.getResult().getId().toString());
        pageQueryPlanLineRequest.setStatus(SalesPlanLineStatusEnum.FINISH.getStatus());
        // 获取总数
        PageResult<List<SalesPlanLineSDO>> pageResultResult = salesPlanLineRepository.pageQuerySalesPlanLineList(pageQueryPlanLineRequest);
        int totalPage = (pageResultResult.getTotal() + SALES_PLAN_LIN_PAGE_SIZE - 1) / SALES_PLAN_LIN_PAGE_SIZE;
        // 明细数据
        List<SalesPlanLineSDO> salesPlanLineSDOList = new ArrayList<>();
        for (int i = 1; i <= totalPage; i++) {
            pageQueryPlanLineRequest.setSize(SALES_PLAN_LIN_PAGE_SIZE);
            pageQueryPlanLineRequest.setPage(i);
            PageResult<List<SalesPlanLineSDO>> pageResultResult2 = salesPlanLineRepository.pageQuerySalesPlanLineList(pageQueryPlanLineRequest);
            if (null == pageResultResult2 || CollectionUtils.isEmpty(pageResultResult2.getContent())) {
                break;
            }
            salesPlanLineSDOList.addAll(pageResultResult2.getContent());
        }
        if (CollectionUtils.isNotEmpty(salesPlanLineSDOList)) {
            // 过滤,创建
            filterPlanLine(salesPlanLineSDOList, salesPlan.getResult());
        }
        return Result.success(true);
    }

    @Resource
    private OpeCustomerAddressIndexService opeCustomerAddressIndexService;

    /**
     * 过滤掉不可用的客户地址+货品范围
     *
     * @param salesPlanLineSDOList 最近上月的明细数据,每页500条数据
     * @param salesPlanSDO         当月计划任务数据
     */
    private void filterPlanLine(List<SalesPlanLineSDO> salesPlanLineSDOList, SalesPlanSDO salesPlanSDO) {
        Set<String> customerAddressSet = salesPlanLineSDOList.stream().map(SalesPlanLineSDO::getCustomerAddress).collect(Collectors.toSet());
        Set<String> addressIdSet = salesPlanLineSDOList.stream().map(SalesPlanLineSDO::getCustomerAddressId).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        // 批量查询客户地址(条件:status=1 启用)
        // TODO 已和产品确认，月度计划中参与送达方最多不会超过500个，limit=1000已满足需求
        PageQueryCustomerAddressFilterRequest addressRequest = new PageQueryCustomerAddressFilterRequest();
        addressRequest.setLimit(1000);
        addressRequest.setStart(0);
        addressRequest.setStatus(1);
        if (CollectionUtils.isNotEmpty(customerAddressSet)) {
            addressRequest.setAddressCodeList(Lists.newArrayList(customerAddressSet));
        }
        if (CollectionUtils.isNotEmpty(addressIdSet)) {
            addressRequest.setIdList(Lists.newArrayList(addressIdSet));
        }
        PageQueryCustomerAddressFilterResponse pageQueryCustomerAddressFilterResponse = opeCustomerAddressIndexService.pageQueryCustomerAddressFilter(addressRequest);
        if (null == pageQueryCustomerAddressFilterResponse || CollectionUtils.isEmpty(pageQueryCustomerAddressFilterResponse.getResult())) {
            log.error("SalesPlanWriteServiceImpl.filterPlanLine customerAddress not found");
            return;
        }
        Map<String, CustomerAddressIndex> customerAddressMap = pageQueryCustomerAddressFilterResponse.getResult().stream().collect(Collectors.toMap(index -> Objects.toString(index.getId(), null), a -> a, (a, b) -> a));

        Set<String> scItemSet = salesPlanLineSDOList.stream().map(SalesPlanLineSDO::getScItemId).collect(Collectors.toSet());
        // 批量查询货品范围(条件:status=1 启用)
        BatchQuerySalesPlanScItemRequest batchQuerySalesPlanScItemRequest = new BatchQuerySalesPlanScItemRequest();
        batchQuerySalesPlanScItemRequest.setScItemIds(Lists.newArrayList(scItemSet));
        batchQuerySalesPlanScItemRequest.setOrgBusinessUnitCodeList(Lists.newArrayList(salesPlanSDO.getOrgBusinessUnitCode()));
        batchQuerySalesPlanScItemRequest.setStatus(1);
        Result<List<SalesPlanScItemSDO>> scItemResult = salesPlanScItemQueryService.batchQuerySalesPlanScItem(batchQuerySalesPlanScItemRequest);
        if (null == scItemResult || CollectionUtils.isEmpty(scItemResult.getResult())) {
            log.error("SalesPlanWriteServiceImpl.filterPlanLine scItemResult not found");
            return;
        }
        // 转map
        Map<String, SalesPlanScItemSDO> scItemMap = scItemResult.getResult().stream().collect(Collectors.toMap(SalesPlanScItemSDO::getScItemId, a -> a, (a, b) -> a));
        // 计划明细防重处理
        Map<String, SalesPlanLineSDO> salesPlanLineSDOMap = salesPlanLineSDOList.stream().collect(Collectors.toMap(salesPlanLineSDO -> salesPlanLineSDO.getCustomerAddressId() + salesPlanLineSDO.getScItemId(),
                a -> a, (a, b) -> a));
        List<SalesPlanLineSDO> request = Lists.newArrayList();
        for (SalesPlanLineSDO salesPlanLineSDO : salesPlanLineSDOMap.values()) {
            CustomerAddressIndex customerAddress = customerAddressMap.get(salesPlanLineSDO.getCustomerAddressId());
            SalesPlanScItemSDO salesPlanScItemSDO = scItemMap.get(salesPlanLineSDO.getScItemId());
            if (Objects.isNull(customerAddress) || StringUtils.isBlank(customerAddress.getPrincipal())) {
                log.warn("无有效的送达方地址:{}", salesPlanLineSDO.getCustomerAddressId());
                continue;
            }
            if (Objects.isNull(salesPlanScItemSDO)) {
                log.warn("无有效的计划货品:{}", salesPlanLineSDO.getScItemId());
                continue;
            }

            SalesPlanLineSDO sdo = SalesPlanLineSDO.builder().build();
            sdo.setPlanId(salesPlanSDO.getId().toString());
            // 地址
            sdo.setChannelCode(customerAddress.getChannelCode());
            sdo.setOrgBusinessUnitCode(customerAddress.getOrgBussinessUnitCode());
            sdo.setOrgSalesOrganizationCode(customerAddress.getOrgSaleOrganizationCode());
            sdo.setOrgSalesChannelCode(customerAddress.getOrgSaleChannelCode());
            sdo.setOrgSalesDepartmentCode(customerAddress.getOrgSaleDepartmentCode());
            sdo.setCustomerCode(customerAddress.getCustomerCode());
            sdo.setCustomerAddress(customerAddress.getAddressCode());
            sdo.setCustomerAddressId(Objects.toString(customerAddress.getId(), null));
            sdo.setManageEmployeeId(customerAddress.getPrincipal());

            // 货品
            sdo.setScItemId(salesPlanScItemSDO.getScItemId());
            sdo.setScItemGroup(salesPlanScItemSDO.getScItemGroup());
            sdo.setScItemLeafCategoryId(salesPlanScItemSDO.getScItemLeafCategoryId());
            sdo.setScItemRootCategoryId(salesPlanScItemSDO.getScItemRootCategoryId());
            sdo.setCostInsuranceFreight(salesPlanScItemSDO.getCostInsuranceFreight());
            sdo.setOutboundPrice(salesPlanScItemSDO.getOutboundPrice());
            sdo.setBasicUnit(salesPlanScItemSDO.getBasicUnit());

            // 量
            // sdo.setMonthCount(salesPlanLineSDO.getTaskCount());
            // sdo.setMonthFirstCount(salesPlanLineSDO.getMonthFirstTaskCount());
            // sdo.setMonthMiddleCount(salesPlanLineSDO.getMonthMiddleTaskCount());
            // sdo.setMonthLastCount(salesPlanLineSDO.getMonthLastTaskCount());
            // sdo.setIsBalanced(Boolean.FALSE);
            // sdo.setStatus(SalesPlanLineStatusEnum.FINISH.getStatus());
            sdo.setStatus(SalesPlanLineStatusEnum.DRAFT.getStatus());
            sdo.setTenantId("mengniu");
            request.add(sdo);
        }
        // 明细数据copy过来一份到新月度计划明细
        salesPlanLineWriteService.batchCreateSalesPlanLine(request);
    }
}
